#include "UsuariosDAO.h"


/* instancia estatica privada del DAO */
UsuariosDAO* UsuariosDAO::instancia = NULL;

/* Datos de MySQL para conexion */
const char* UsuariosDAO::servidor = "localhost";
const int UsuariosDAO::puerto = 3306;
const char* UsuariosDAO::nombreBD = "tp_taller";
const char* UsuariosDAO::usuario = "root";
const char* UsuariosDAO::password = "root";


/* Constructor protected para evitar creacion de nuevas instancias */
UsuariosDAO::UsuariosDAO(void) {
}


/* Destructor publico */
UsuariosDAO::~UsuariosDAO(void) {
}


/* Metodo publico para acceder a la unica instancia privada */
UsuariosDAO* UsuariosDAO::getInstancia() {
	if (instancia == NULL) {
		instancia = new UsuariosDAO();
	}
	return instancia;
}


/* Metodo que devuelve una Lista de Usuarios a partir de vector de mysqlpp */
Lista<Usuario*>* UsuariosDAO::cargarUsuarios(vector<mysqlpp::Row> v) {
	
	Lista<Usuario*>* listaUsuarios = new Lista<Usuario*>();

	for (vector<mysqlpp::Row>::iterator it = v.begin(); it != v.end(); ++it) {
		Usuario* usuario = new Usuario();
		usuario->setId((string)it->at(0));
		usuario->setNombre((string)it->at(1));
		usuario->setPass((string)it->at(2));
		usuario->setPartidasJugadas((int)it->at(3));
		usuario->setPartidasGanadas((int)it->at(4));
		usuario->setPartidasPerdidas((int)it->at(5));
		usuario->setPuntosGanados((int)it->at(6));
		usuario->setTiempoJugado((int)it->at(7));
		
		listaUsuarios->agregar(usuario);
	}
	return listaUsuarios;
}

/* Metodo que devuelve una Lista de Usuarios a partir de vector de mysqlpp */
Lista<PartidaPersistente*>* UsuariosDAO::cargarPartidas(vector<mysqlpp::Row> v) {
	
	Lista<PartidaPersistente*>* listaPartidas = new Lista<PartidaPersistente*>();

	for (vector<mysqlpp::Row>::iterator it = v.begin(); it != v.end(); ++it) {
		PartidaPersistente* partida = new PartidaPersistente();
		partida->setId((string)it->at(0));
		partida->setNombreJugador1((string)it->at(1));
		partida->setNombreJugador2((string)it->at(2));
		partida->setNombreGanador((string)it->at(3));
		partida->setPuntosJugador1((int)it->at(4));
		partida->setPuntosJugador2((int)it->at(5));
		partida->setTiempoPartida((int)it->at(6));
		
		listaPartidas->agregar(partida);
	}
	return listaPartidas;
}


/* Devuelve un count de la tabla de 'usuarios' */
long long UsuariosDAO::contarUsuarios() {
	
	mysqlpp::Connection conn(false);

	try { 
		conn.connect(UsuariosDAO::nombreBD, UsuariosDAO::servidor, UsuariosDAO::usuario, UsuariosDAO::password, UsuariosDAO::puerto);
		//cout << "conexion establecida" << endl;
		long long cantidadUsuarios = conn.count_rows("usuarios");
		conn.disconnect();
		//cout << cantidadUsuarios << endl;
		return cantidadUsuarios;
	}
	catch (const mysqlpp::Exception& er) {
		// Catch-all for any other MySQL++ exceptions
		cerr << "Error: " << er.what() << endl;
		system("pause");
		return -1;
	}
}

Lista<Usuario*>* UsuariosDAO::getMejoresUsuariosPorPartidasGanadas() {

	Lista<Usuario*>* listaUsuarios = new Lista<Usuario*>();
	mysqlpp::Connection conn(false);
	
	try { 
		conn.connect(UsuariosDAO::nombreBD, UsuariosDAO::servidor, UsuariosDAO::usuario, UsuariosDAO::password, UsuariosDAO::puerto);
			
		mysqlpp::Query query = conn.query("");
		query.reset();
		query << " select * from usuarios order by partidasGanadas desc";
		
		vector<mysqlpp::Row> v;
		query.storein(v);

		conn.disconnect();
		return cargarUsuarios(v);
	}
	catch (const mysqlpp::Exception& er) {
		cerr << "Error: " << er.what() << endl;
		system("pause");
		return NULL;
	}
}

Lista<Usuario*>* UsuariosDAO::getMejoresUsuariosPorPartidasJugadas() {

	mysqlpp::Connection conn(false);
	
	try { 
		conn.connect(UsuariosDAO::nombreBD, UsuariosDAO::servidor, UsuariosDAO::usuario, UsuariosDAO::password, UsuariosDAO::puerto);
			
		mysqlpp::Query query = conn.query("");
		query.reset();
		query << " select * from usuarios order by partidasJugadas desc";
		
		vector<mysqlpp::Row> v;
		query.storein(v);

		conn.disconnect();
		return cargarUsuarios(v);
	}
	catch (const mysqlpp::Exception& er) {
		cerr << "Error: " << er.what() << endl;
		system("pause");
		return NULL;
	}
}

Lista<Usuario*>* UsuariosDAO::getMejoresUsuariosPorPuntos() {

	mysqlpp::Connection conn(false);
	
	try { 
		conn.connect(UsuariosDAO::nombreBD, UsuariosDAO::servidor, UsuariosDAO::usuario, UsuariosDAO::password, UsuariosDAO::puerto);
			
		mysqlpp::Query query = conn.query("");
		query.reset();
		query << " select * from usuarios order by puntosGanados desc";
		
		vector<mysqlpp::Row> v;
		query.storein(v);

		conn.disconnect();
		return cargarUsuarios(v);
	}
	catch (const mysqlpp::Exception& er) {
		cerr << "Error: " << er.what() << endl;
		system("pause");
		return NULL;
	}
}

Lista<Usuario*>* UsuariosDAO::getMejoresUsuariosPorTiempoJugado() {

	mysqlpp::Connection conn(false);
	
	try { 
		conn.connect(UsuariosDAO::nombreBD, UsuariosDAO::servidor, UsuariosDAO::usuario, UsuariosDAO::password, UsuariosDAO::puerto);
			
		mysqlpp::Query query = conn.query("");
		query.reset();
		query << " select * from usuarios order by tiempoJugado desc";
		
		vector<mysqlpp::Row> v;
		query.storein(v);

		conn.disconnect();
		return cargarUsuarios(v);
	}
	catch (const mysqlpp::Exception& er) {
		cerr << "Error: " << er.what() << endl;
		system("pause");
		return NULL;
	}
}


Lista<Usuario*>* UsuariosDAO::getTodosLosUsuarios() {

	Lista<Usuario*>* listaUsuarios;
	mysqlpp::Connection conn(false);
	
	try { 
		conn.connect(UsuariosDAO::nombreBD, UsuariosDAO::servidor, UsuariosDAO::usuario, UsuariosDAO::password, UsuariosDAO::puerto);
		//cout << "conexion establecida" << endl;
		
		mysqlpp::Query query = conn.query("");
		query.reset();
		query << "select * from usuarios";
		//cout << "Query: " << query << endl;
		
		vector<mysqlpp::Row> v;
		query.storein(v);
		
		listaUsuarios = cargarUsuarios(v);
		
		return listaUsuarios;
	}
	catch (const mysqlpp::BadQuery& er) {
		// Handle any query errors
		cerr << "Query error: " << er.what() << endl;
		system("pause");
		return NULL;
	}
	catch (const mysqlpp::BadConversion& er) {
		// Handle bad conversions
		cerr << "Conversion error: " << er.what() << endl <<
				"\tretrieved data size: " << er.retrieved <<
				", actual size: " << er.actual_size << endl;
		system("pause");
		return NULL;
	}
	catch (const mysqlpp::Exception& er) {
		// Catch-all for any other MySQL++ exceptions
		cerr << "Error: " << er.what() << endl;
		system("pause");
		return NULL;
	}

}
/* 
	Metodo que guarda un nuevo registro en la tabla de usuarios con el nombre y password parametros.
	Se guardan con valor 0 el resto de las columnas.
*/
void UsuariosDAO::insertarNuevoUsuario(string nombre, string password) {
	
	mysqlpp::Connection conn(false);
	try { 
		conn.connect(UsuariosDAO::nombreBD, UsuariosDAO::servidor, UsuariosDAO::usuario, UsuariosDAO::password, UsuariosDAO::puerto);
		
		mysqlpp::Query query = conn.query();
		query << "insert into usuarios (nombre,password,partidasJugadas,partidasGanadas,partidasPerdidas,puntosGanados,tiempoJugado) " <<
					"values ('" << nombre << "','" << password << "'," <<
					"0,0,0,0,0)";
		
		query.execute();		
	}
	catch (const mysqlpp::Exception& er) {
		cerr << "Error: " << er.what() << endl;
	}
}

/*
	Metodo que actualiza los datos de un jugador despues de una partida usando el nombre como identificador.
	Se incrementa en 1 las partidas jugadas.
	Se incrementa en 1 las partidas ganadas o perdidas segun si haGanado.
	Si haEmpatado no se incrementa ni partidaGanadas ni partidaPerdidas
	Se incrementan los nuevos puntos obtenidos.
	Se incrementan el tiempo jugado.
*/
void UsuariosDAO::actualizarEstadisticaDeJugador(string nombre, int puntosGanados, bool haGanado, bool haEmpatado, int tiempoJugado) {
	
	mysqlpp::Connection conn(false);
	try {
		int incrementarPartGan = 0;
		int incrementarPartPer = 0;
		
		if (!haEmpatado) {
			if (haGanado) {
				incrementarPartGan = 1;
			}
			else {
				incrementarPartPer = 1;
			}
		}
		conn.connect(UsuariosDAO::nombreBD, UsuariosDAO::servidor, UsuariosDAO::usuario, UsuariosDAO::password, UsuariosDAO::puerto);

		mysqlpp::Query query = conn.query();
		query << "update usuarios set partidasJugadas=partidasJugadas+1, " <<
			"partidasGanadas=partidasGanadas+" << incrementarPartGan << ", " <<
			"partidasPerdidas=partidasPerdidas+" << incrementarPartPer << ", " <<
			"puntosGanados=puntosGanados+" << puntosGanados << ", " <<
			"tiempoJugado=tiempoJugado+" << tiempoJugado << " " <<
			"where nombre = '" << nombre << "'";

//		cout << query << endl;
		query.execute();		
	}
	catch (const mysqlpp::Exception& er) {
		cerr << "Error: " << er.what() << endl;
	}
}

void UsuariosDAO::insertarNuevaPartida(string nombreJugador1, string nombreJugador2, 
		string nombreGanador, int puntos1, int puntos2, int tiempoJugado) {
	
	mysqlpp::Connection conn(false);
	try {
		conn.connect(UsuariosDAO::nombreBD, UsuariosDAO::servidor, UsuariosDAO::usuario, UsuariosDAO::password, UsuariosDAO::puerto);

		mysqlpp::Query query = conn.query();
		query << "insert into partidas (nombreJugador1,nombreJugador2,nombreGanador,puntosJugador1,puntosJugador2,tiempoPartida) values ('" << nombreJugador1 << "','" <<
			nombreJugador2 << "','" << nombreGanador << "'," << puntos1 << "," <<
			puntos2 << "," << tiempoJugado << ")";
//		cout << query << endl;
		query.execute();		
	}
	catch (const mysqlpp::Exception& er) {
		cerr << "Error: " << er.what() << endl;
	}
}



Lista<PartidaPersistente*>* UsuariosDAO::getPartidasEntreUsuarios(string usuario1, string usuario2) {

	mysqlpp::Connection conn(false);
	
	try { 
		conn.connect(UsuariosDAO::nombreBD, UsuariosDAO::servidor, UsuariosDAO::usuario, UsuariosDAO::password, UsuariosDAO::puerto);
			
		mysqlpp::Query query = conn.query("");
		query.reset();
		query << " select * from partidas where (nombreJugador1 ='" <<
			usuario1 << "' and nombreJugador2 = '"<< usuario2 << "') or (nombreJugador2='" <<
			usuario1 << "' and nombreJugador1='" << usuario2 << "')";
		vector<mysqlpp::Row> v;
		query.storein(v);

		conn.disconnect();
		return cargarPartidas(v);
	}
	catch (const mysqlpp::Exception& er) {
		cerr << "Error: " << er.what() << endl;
		system("pause");
		return NULL;
	}
}